#coding: latin1

## Copyright Luc Saffre 2003-2004.

## This file is part of the Lino project.

## Lino is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.

## Lino is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
## or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
## License for more details.

## You should have received a copy of the GNU General Public License
## along with Lino; if not, write to the Free Software Foundation,
## Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

import os

from lino.ui import console
from lino.misc.restify import reSTify 
from lino.webman import __version__
from lino.twisted_ui.response import HtmlResponse

class WebManException(Exception):
    pass


class WebmanResponse(HtmlResponse):
    def __init__(self,node):
        assert isinstance(node,Node)
        self.node = node
        HtmlResponse.__init__(self,None)

##  def nodeDir(self):
##      return self.node.getLocalPath()

    def getTitle(self):
        return self.node.getTitle()
        
    def homeURI(self,*args,**kw):
        #url = self.getModule().site.
        return self.buildURL(".",
                                    *(self.node.getLocation()+list(args)),**kw)
    
    def uriToSelf(self,*args,**kw):
        return self.homeURI( self.node.getOutputFile())

    def getStyleSheet(self):
        return self.node.getModule().getStyleSheet()
    
    def writeLeftMargin(self):
        m = self.node.getModule().leftArea
        if m is not None:
            m(self)
        
    def writePreTitle(self):
        m = self.node.getModule().preTitle
        if m is None:
            for p in self.node.getParents():
                self.renderLink(p.getURL(self.node),p.getTitle())
                self.write(" &middot; ")
        else:
            m(self)
        
    def writeLeftFooter(self):
        self.write("""
        <font size=1>
        Generated by <a href="%s" target="_top">Lino/Webman</a>
        version %s.
        </font>
        """ % (self.homeURI(),__version__))
    
    def writePage(self):
        self.node.writePageContent(self)

    def writeSiteMap(self):
        mod = self.node.getModule()
        if mod.site.menu is None:
            pass
        else:
            self.write(mod.site.menu.render_html(self.node.menuItem))
        

class Node:
    isMenuItem = False
    def __init__(self, site, name, parent ):
        self.site = site
        self.parent = parent
        self.title = None
        self.abstract = None
        self.name = name # os.path.dirname(self.__module__.__file__)
        self.modified = None
        self.menuItem = None

    def setTitle(self,title):
        self.title = title

    def setMenuItem(self,item):
        assert item.node == self
        self.menuItem = item

    def getTitle(self):
        return self.title

    def getChildren(self):
        return []

    def setAbstract(self,abstract):
        self.abstract = abstract

##  def getSourcePath(self):
##      raise NotImplementedError
    
    def dependsOn(self,pfn):
        self.touch(os.path.getmtime(pfn))
        
    def touch(self,mtime):
        self.modified = max( self.modified, mtime)
        if self.parent is not None:
            self.parent.touch(mtime)
            
    def getParents(self):
        l = []
        p = self.parent
        while p is not None:
            l.insert(0,p)
            p = p.parent
        return l
    
        
    def getModule(self):
        raise NotImplementedError

    def init(self):
        pass
    
    def render_html(self,request):
        r = WebmanResponse(self)
        r.writeWholePage()
        return r._writer.getvalue()
        
    def __str__(self):
        return "/".join(self.getLocation())+"/"+self.getOutputFile()

    def writeAbstract(self,response):
        response.renderLink(self.getURL(response.node),
                                  label=self.getTitle())
    def getOutputFile(self):
        """return name of file to be generated,
        relative to self.getLocation()"""
        return self.name + ".html"

    def getLocation(self):
        "directory part of full output file"
        raise NotImplementedError
        

##  def getFileName(self):
##      return self.name + ".html"
    
    def getURL(self,fromNode=None):
        #nodeFile = self.getFileName()
        if fromNode is None or fromNode.getModule() == self.getModule():
            # URL for a link from same directory
            return self.getOutputFile()
        fromBase = fromNode.getLocation()#.split(os.sep)
        toBase = self.getLocation()#.split(os.sep)
        while True:
            if len(fromBase) == 0: break
            if len(toBase) == 0: break
            if fromBase[0] == toBase[0]:
                del fromBase[0]
                del toBase[0]
            else:
                break
        url = ""
        #print "from", str(fromBase)
        #print "to", str(toBase)
        for elem in fromBase:
            url += "../"
        for elem in toBase:
            url += elem + "/"
        return url + self.getOutputFile()


class RootNode(Node):
    def __init__(self,mod):
        Node.__init__(self,mod.site,'index',mod)

    def writePageContent(self,response):
        pass

    
class WebModule(Node):
    
    """ webman creates one instance of this for each directory in the
    tree """
    
    isMenuItem = True
    def __init__(self, site, name, parent):
        """
        `localPath` : local directory 
        """
        self.filerefBase = None
        self.filerefURL = None
        self.root = None

        
        Node.__init__(self,site,name,parent)
        
        self.argv = ['--traceback']
        
        # private members:
        self._q_exports = ['default.css']
        self._nodes = {}
        self._images = []

        if parent is None:
            self.location = []
        else:
            self.location = parent.getLocation() + [name]

        localPath = self.getLocalPath()
        if not os.path.isdir(localPath):
            raise WebManException("%s is not a directory" % localPath)
        #self.localPath = localPath

        console.debug("Loading Webman module from %s..." % localPath)

        #raise "bla"
        # scan directory 

        for fn in os.listdir(localPath):
            (name,ext) = os.path.splitext(fn)
            if len(name) and name[0] != "_":
                pfn = os.path.join(localPath,fn)
                node = None
                if ext == ".txt":
                    node = TxtWebPage(self,name,ext)
                elif ext == ".jpg":
                    #self.addImage(name,ext)
                    node = ImgWebPage(self,name,ext,len(self._images))
                    self._images.append(node)
                elif ext == '':
                    if os.path.isdir(pfn):
                        node = WebModule(self.site,fn,parent=self)
                if node is not None:
                    if name == self.name: #'index':
                        self.root = node
                    else:
                        self.addNode(name,node)
        #from time import localtime
        #print localtime(self.modified)
        #self._q_index = self
        self.title = self.name
        if self.root is None:
            self.root = RootNode(self)

        
    def getOutputFile(self):
        """return name of file to be generated,
        relative to self.getLocation()"""
        return self.root.getOutputFile()

    def getLocation(self):
        return self.location
    
    def getLocalPath(self):
        #print self.site.sourceRoot
        #print self.location
        return os.path.join(self.site.sourceRoot,*self.location)
    
    def writePageContent(self,response):
        self.root.writePageContent(response)
        wr= response.write
        if len(self.getChildren()):
            wr("<ul>")
            for child in self.getChildren():
                wr("<li>")
                child.writeAbstract(response)
                wr("</li>")
            wr("</ul>")
        if len(self._images):
            for img in self._images:
                response.renderLink(img.getURL(),img.getTitle())

    def init(self):

        if self.parent is None:
            #self.menu = None
            self.preTitle = None
            self.leftArea = None
            self.topArea = None
            self.bottomArea = None
            self.defaults = {
                'input_encoding': 'latin-1',
                'output_encoding': 'latin-1',
                'stylesheet': 'default.css',
                #'traceback': True,
                #'embed_stylesheet': False,
                #'source_link': 0,
                'tab_width': 3,
                #'datestamp' : None, # '%Y-%m-%d %H:%M UTC',
                #'generator': 0 
                }
            #self._oopsNode = None
        else:
            # inherit from parent
            parent = self.parent
            self.preTitle = parent.preTitle
            self.leftArea = parent.leftArea
            #self.menu = parent.menu
            self.topArea = parent.topArea
            self.bottomArea = parent.bottomArea
            self.defaults = dict(parent.defaults)
            self.defaults['stylesheet'] = "../" + \
              self.defaults['stylesheet']
            #self.defaults['stylesheet_path'] = "../" + \
            #  self.defaults['stylesheet_path']
            #print "TODO: " + self.defaults['stylesheet_path']
            if parent.filerefBase is not None:
                self.filerefBase = os.path.join(parent.filerefBase,"..")
            #self._oopsNode = parent._oopsNode
        
        
        fn = os.path.join(self.getLocalPath(),'init.wmi')
        if os.path.exists(fn):
            self.dependsOn(fn)
            cwd = os.getcwd()
            os.chdir(self.getLocalPath())
            execfile('init.wmi')
            os.chdir(cwd)
        else:
            self.addToSitemap()

        for node in self._nodes.values():
            node.init()
            
        #assert self.modified is not None, self.getLocation()


    def setMenu(self,menuText):
        # deprecated: replace by addToSitemap()
        return self.addToSitemap(menuText)
    
    def addToSitemap(self,menuText=None):
        self.site.addToSitemap(self,menuText)
        
        
    def getSourcePath(self):
        return self.root.getSourcePath()
        #return os.path.join(self.getLocalPath(), 'index.txt')
    
    def getModule(self):
        return self

    def getChildren(self):
        return self._nodes.values()
    
    def getChild(self,name):
        return self._nodes[name]
    
    def setStyleSheet(self,name):
        self.defaults['stylesheet']=name
        
    def getStyleSheet(self):
        return self.defaults['stylesheet']

    def setFilerefBase(self,pth):
        self.filerefBase = pth

    def setFilerefURL(self,url):
        
        """ Set URL pattern for `fileref` roles `url` must be a string
        containing one '%s' which will be replaced by the fileref
        text. The result should be a valid URI.  """

        self.filerefURL = url
        
    def setLeftArea(self,f):
        self.leftArea = f
        
    def setPreTitle(self,f):
        self.preTitle = f
        
    def setBottomArea(self,f):
        self.bottomArea = f

##  def getLocalPath(self):
##      return self.localPath

    def getPages(self):
        return self._nodes.values()

    def addNode(self,name,page):
        if self._nodes.has_key(name):
            raise WebManException('Duplicate definition for node %s' % name)
        self._nodes[name] = page
        self._q_exports.append(name)
        
        
##  def leftArea(self,page=None):
##      return """<a href="index.html">Home</a>
##      <br>Hint:
##      <br>set self.leftArea()!
##      """

    def __getattr__(self,name):
        try:
            return self._nodes[name]
        except KeyError,e:
            raise AttributeError,name

    #def _q_access(self,request):
    #   pass
    
    
class FileNode(Node):
    def __init__(self,mod,name,ext,title=None):
        Node.__init__(self,mod.site,name,parent=mod)
        if title is None:
            title = name
        self.title = title
        self.ext = ext
        self.dependsOn(self.getSourcePath())

    def getLocation(self):
        return self.parent.getLocation()
        
    def getModule(self):
        return self.parent
    
    def getSourcePath(self):
        return os.path.join(self.parent.getLocalPath(), self.name)\
                 + self.ext
    
class TxtWebPage(FileNode):
    """
    TODO: self.title should be set by the docutils parser
    """
    
    isMenuItem = True
    
    def writePageContent(self,response):
        fn = self.getSourcePath()
        #if os.path.exists(fn):
        cwd = os.getcwd()
        os.chdir(self.getModule().getLocalPath())
        response.write(
            reSTify(open(fn).read(),
                    source_path=fn,
                    namespace={ "node":self,
                                "response":response },
                    settings=self.getModule().defaults))
##          try:
##              response.write(
##                  reSTify(open(fn).read(),
##                            namespace={ "node":self,
##                                            "response":response },
##                            settings=self.getModule().defaults))
##          except Exception,e:
##              print str(e)
##          else:
##              os.chdir(cwd)
        os.chdir(cwd)            

        
    
class ImgWebPage(FileNode):
    def __init__(self,mod,name,ext,index):
        FileNode.__init__(self,mod,name,ext)
        self.index = index
    
    def writePageContent(self,response):
        wr = response.write
        mod = self.getModule()
        if self.index > 0:
            wr("""\n<a href="%s">prev</a>""" % \
                  mod._images[self.index-1].getOutputFile())
        if self.index+1 < len(mod._images):
            wr("""\n<a href="%s">next</a>""" % \
                  mod._images[self.index+1].getOutputFile())
        wr("<p>")
        wr("""<img src="%s" width="90%%">""" % (self.name+self.ext))
    
